package edu.cicese.alz;

import edu.cicese.alz.swing.CustomButton;
import edu.cicese.alz.swing.CustomToggleButton;
import edu.cicese.alz.swing.JSystemFileChooser;
import edu.cicese.alz.swing.SortedListModel;
import edu.cicese.alz.swing.SwingUtil;
import edu.cicese.alz.swing.ToggleButtonMouseListener;
import edu.cicese.alz.swing.dialogs.ConfirmationDialog;
import edu.cicese.alz.swing.progress.ProgressMonitor;
import edu.cicese.alz.swing.progress.ProgressUtil;
import edu.cicese.alz.util.JSON;
import edu.cicese.alz.util.PropertyUtil;
import edu.cicese.alz.util.Utilities;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;

import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 6/06/12
 * Time: 01:09 PM
 */
public class FrameCreateDSV extends SwingComponent {

	private SortedListModel dlmSortedSelectedSubjects;
	private DefaultListModel dlmUnsortedSelectedSubjects;
	private JList lSubjects, lSelectedSubjects, lPaths;
	private DefaultListModel dlmSubjects, dlmPaths;

	private AbstractButton btnOk;
	private CustomButton btnAdd, btnRemove, btnAll, btnNone, btnCancelSelected;
	private CustomButton btnExplore, btnCreate;

	private List<Subject> idxSubjectsPerRow = new ArrayList<>();
	private Map<Integer, Subject> idxSubjectsPerID = new HashMap();
	private Map<Integer, Source> idxSelectedSubjects = new HashMap();

	private int cTable, cAccelerometer;

	private JSystemFileChooser fcHomeDir;

	public FrameCreateDSV() {
		super(1100, 500, "Create DSV files");

		initComponents();

		fillSubjects(Query.getSubjects());
//		fillSubjectsDemo();

		enableComponents();
	}


	private void initComponents() {
		dlmSubjects = new DefaultListModel();
		dlmPaths = new DefaultListModel();

		lSubjects = new JList(dlmSubjects);
		lSubjects.setCellRenderer(new SelectedListCellRenderer());
		lSubjects.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		lSubjects.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2 && !e.isConsumed()) {
					e.consume();
					selectSubject();
				}
			}
		});
		lSubjects.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_INSERT) {
					selectSubject();
				}
			}
		});

		dlmUnsortedSelectedSubjects = new DefaultListModel();
		dlmSortedSelectedSubjects = new SortedListModel(dlmUnsortedSelectedSubjects);
		lSelectedSubjects = new JList();
		lSelectedSubjects.setModel(dlmSortedSelectedSubjects);
		lSelectedSubjects.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_DELETE) {
					removeSubject();
				}
			}
		});

		lPaths = new JList(dlmPaths);
		lPaths.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		lPaths.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_DELETE) {
					for (Integer index : lPaths.getSelectedIndices()) {
//						dlmPaths.set(index, "");
						idxSelectedSubjects.get(getUserID(dlmSortedSelectedSubjects.getElementAt(index).toString())).getPaths().clear();
						updatePaths();
					}
				}
			}
		});
		lPaths.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2 && !e.isConsumed() && lPaths.getSelectedIndex() != -1 && btnOk.isSelected()) {
					e.consume();
					openFileChooser(lPaths.getSelectedIndex());
				}
			}
		});
		lPaths.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				lSelectedSubjects.setSelectedIndices(lPaths.getSelectedIndices());
			}
		});


		JScrollPane spSubjects = new JScrollPane(lSubjects);
		spSubjects.setMinimumSize(new Dimension(200, 1000));
		spSubjects.setPreferredSize(new Dimension(200, 1000));
		spSubjects.setMaximumSize(new Dimension(400, 1000));

		JScrollPane spSelectedSubjects = new JScrollPane(lSelectedSubjects);
		spSelectedSubjects.setMinimumSize(new Dimension(200, 1000));
		spSelectedSubjects.setPreferredSize(new Dimension(200, 1000));
		spSelectedSubjects.setMaximumSize(new Dimension(400, 1000));

		JScrollPane spPaths = new JScrollPane(lPaths);
		spPaths.getVerticalScrollBar().setModel(spSelectedSubjects.getVerticalScrollBar().getModel());


		JLabel lblSubjects = new JLabel("Subjects");
		JLabel lblSelectedSubjects = new JLabel("Selected");
		JLabel lblPath = new JLabel("Source paths");


		btnAdd = createCustomButton("", "Add selected", "b_add");
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionAdd();
			}
		});
		btnRemove = createCustomButton("", "Remove selected", "b_remove");
		btnRemove.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionRemove();
			}
		});
		btnAll = createCustomButton("", "Select all", "b_select_all");
		btnAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionAll();
			}
		});
		btnNone = createCustomButton("", "Select none", "b_select_none");
		btnNone.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionNone();
			}
		});

		Box boxPaneSubjects = Box.createVerticalBox();
		boxPaneSubjects.add(btnAdd);
		boxPaneSubjects.add(btnRemove);
		boxPaneSubjects.add(btnAll);
		boxPaneSubjects.add(btnNone);


		if (!UIManager.getLookAndFeel().getName().equals("Windows")) {
			btnOk = createCustomToggleButton("", null, "b_ok");
			btnOk.addMouseListener(new ToggleButtonMouseListener((CustomToggleButton) btnOk));
		} else {
			btnOk = createToggleButton("", null, "b_ok");
		}

		btnOk.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionOK();
			}
		});
		btnCancelSelected = createCustomButton("", "Clear selection", "b_clear");
		btnCancelSelected.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionCancelSelected();
			}
		});

		Box boxPaneSelectedSubjects = Box.createVerticalBox();
		boxPaneSelectedSubjects.add(btnOk);
		boxPaneSelectedSubjects.add(btnCancelSelected);

		btnExplore = createCustomButton("Explore", "Select JSON files", "search", 72, 24);
		btnExplore.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openFileChooser();
			}
		});
		btnCreate = createCustomButton("Create", "Create DSV files", "create", 72, 24);
		btnCreate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionCreate();
			}
		});
		JButton btnCancel = createCustomButton("Cancel", "Cancel DSV file creation", "cancel", 72, 24);
		btnCancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionCancel();
			}
		});

		Box boxPaneMain = Box.createVerticalBox();
		boxPaneMain.add(btnExplore);
		boxPaneMain.add(Box.createVerticalGlue());
		boxPaneMain.add(btnCreate);
		boxPaneMain.add(Box.createVerticalStrut(10));
		boxPaneMain.add(btnCancel);
		boxPaneMain.add(Box.createVerticalStrut(4));

		JPanel pContent = new JPanel(new GridBagLayout());
		pContent.setBackground(SwingUtil.cBackground);

		GridBagConstraints gbc = new GridBagConstraints();

		// Row 1
		gbc.insets = new Insets(5, 5, 0, 5);
		gbc.gridx = 0;
		gbc.gridy = 0;
		pContent.add(lblSubjects, gbc);

		gbc.gridx = 2;
		gbc.gridy = 0;
		pContent.add(lblSelectedSubjects, gbc);

		gbc.gridx = 4;
		gbc.gridy = 0;
		pContent.add(lblPath, gbc);


		// Row 2
		gbc.insets = new Insets(3, 5, 5, 1);
		gbc.fill = GridBagConstraints.BOTH;
		gbc.anchor = GridBagConstraints.FIRST_LINE_START;
		gbc.gridx = 0;
		gbc.gridy = 1;
		gbc.weighty = 1.0;
		gbc.weightx = 0;
		pContent.add(spSubjects, gbc);

		gbc.insets = new Insets(3, 1, 5, 1);
		gbc.gridx = 1;
		gbc.gridy = 1;
		gbc.weightx = 0;
		pContent.add(boxPaneSubjects, gbc);

		gbc.gridx = 2;
		gbc.gridy = 1;
		gbc.weighty = 1.0;
		gbc.weightx = 0;
		pContent.add(spSelectedSubjects, gbc);

		gbc.gridx = 3;
		gbc.gridy = 1;
		gbc.weightx = 0;
		pContent.add(boxPaneSelectedSubjects, gbc);

		gbc.gridx = 4;
		gbc.gridy = 1;
		gbc.weighty = 1.0;
		gbc.weightx = 0.5;
		pContent.add(spPaths, gbc);

		gbc.insets = new Insets(5, 5, 5, 5);
		gbc.gridx = 5;
		gbc.gridy = 1;
		gbc.weightx = 0;
		pContent.add(boxPaneMain, gbc);

		setContentPane(pContent);
	}


	private void fillSubjects(ResultSet resultSet) {
		dlmSubjects.clear();
		idxSubjectsPerRow.clear();
		idxSubjectsPerID.clear();
		try {
			if (resultSet != null) {
				int userID;
				while (resultSet.next()) {
					userID = resultSet.getInt(1);
					Subject subject = new Subject(userID);
					idxSubjectsPerRow.add(subject);
					idxSubjectsPerID.put(userID, subject);
					dlmSubjects.addElement(userID + getSpaces(userID) + resultSet.getString(2));
				}
			} else {
				Query.showConnectionError(this);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			Query.close();
		}
	}

	private void fillSubjectsDemo() {
		dlmSubjects.clear();
		idxSubjectsPerRow.clear();
		idxSubjectsPerID.clear();
		for (int userID = 1; userID < 31; userID++) {
			Subject subject = new Subject(userID);
			idxSubjectsPerRow.add(subject);
			idxSubjectsPerID.put(userID, subject);
			dlmSubjects.addElement(userID + getSpaces(userID));
		}
	}

	private void actionAdd() {
		selectSubject();
	}

	private void actionRemove() {
		removeSubject();
	}

	private void actionAll() {
		lSubjects.setSelectionInterval(0, lSubjects.getModel().getSize() - 1);
	}

	private void actionNone() {
		lSubjects.clearSelection();
	}

	private void actionOK() {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				enableComponents();
			}
		});
	}

	private void actionCancelSelected() {
//		dlmSortedSelectedSubjects.
		int userID;
		for (int i = 0; i < dlmUnsortedSelectedSubjects.size(); i++) {
			userID = getUserID(dlmUnsortedSelectedSubjects.get(i).toString());
			idxSubjectsPerID.get(userID).setSelected(false);
			idxSelectedSubjects.remove(userID);
		}
		dlmUnsortedSelectedSubjects.removeAllElements();
		updatePaths();
		lSubjects.repaint();
	}

	private void selectSubject() {
		Subject subject;
		for (int index : lSubjects.getSelectedIndices()) {
			subject = idxSubjectsPerRow.get(index);
			if (!subject.isSelected()) {
				subject.setSelected(true);
				dlmUnsortedSelectedSubjects.addElement(dlmSubjects.get(index));
				idxSelectedSubjects.put(subject.getUserID(), new Source(dlmUnsortedSelectedSubjects.getElementAt(dlmUnsortedSelectedSubjects.getSize() - 1)));
			}
		}
		updatePaths();
		lSubjects.repaint();
	}

	private void removeSubject() {
		int[] unsortedSelection = dlmSortedSelectedSubjects.toUnsortedModelIndices(lSelectedSubjects.getSelectedIndices());
		int userID;
		for (int x = unsortedSelection.length - 1; x >= 0; --x) {
			userID = getUserID(dlmUnsortedSelectedSubjects.get(unsortedSelection[x]).toString());
			idxSubjectsPerID.get(userID).setSelected(false);
			idxSelectedSubjects.remove(userID);
			dlmUnsortedSelectedSubjects.remove(unsortedSelection[x]);
		}
		updatePaths();
		lSubjects.repaint();
	}


	private void updatePaths() {
		dlmPaths.clear();
		dlmPaths.setSize(idxSelectedSubjects.size());
		for (Map.Entry<Integer, Source> subject : idxSelectedSubjects.entrySet()) {
			Source source = subject.getValue();
			dlmPaths.set(dlmSortedSelectedSubjects.toSortedModelIndex(dlmUnsortedSelectedSubjects.indexOf(source.getObject())), source.getPath());
		}
	}

	//TODO setCurrentDirectory
	//TODO clear after creating dsv files
	private void openFileChooser() {
		if (fcHomeDir == null) {
			fcHomeDir = new JSystemFileChooser();
		}
		fcHomeDir.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		fcHomeDir.setMultiSelectionEnabled(true);
		fcHomeDir.setDialogTitle("Select source folder(s)");
		fcHomeDir.setApproveButtonToolTipText("Select source folders(s)");

		SwingUtil.clearSystemFileChooser(fcHomeDir);
//		fcHomeDir.setCurrentDirectory(new File(prevDir));
		File[] dirs;
		if (fcHomeDir.showDialog(this, "Select") == JFileChooser.APPROVE_OPTION) {
			dirs = fcHomeDir.getSelectedFiles();
			if (dirs != null) {
				for (int index = 0; index < dirs.length && index < idxSelectedSubjects.size(); index++) {
					File dir = dirs[index];
//					dlmPaths.set(index, dir);
					idxSelectedSubjects.get(getUserID(dlmSortedSelectedSubjects.getElementAt(index).toString())).appendPath(dir.getPath());
					updatePaths();
				}
			}
			enableComponents();
		}
	}

	private void openFileChooser(int index) {
		if (fcHomeDir == null) {
			fcHomeDir = new JSystemFileChooser();
		}
		fcHomeDir.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		fcHomeDir.setMultiSelectionEnabled(true);
		fcHomeDir.setDialogTitle("Select source folder(s)");
		fcHomeDir.setApproveButtonToolTipText("Select source folders(s)");
		fcHomeDir.setCurrentDirectory(new File(dlmPaths.get(index).toString()));

		SwingUtil.clearSystemFileChooser(fcHomeDir);

		if (fcHomeDir.showDialog(this, "Select") == JFileChooser.APPROVE_OPTION) {
			File[] dirs = fcHomeDir.getSelectedFiles();
			if (dirs != null) {
				String dirsS = "";
				for (int i = 0; i < dirs.length; i++) {
					dirsS += dirs[i] + ";";
				}
//				dlmPaths.set(index, dirsS);
				idxSelectedSubjects.get(getUserID(dlmSortedSelectedSubjects.getElementAt(index).toString())).appendPath(dirs);
				updatePaths();
			}
			enableComponents();
		}
	}

	private boolean showMissingPathDialog() {
		boolean okd = true;
		for (Map.Entry<Integer, Source> subject : idxSelectedSubjects.entrySet()) {
			if (!subject.getValue().hasPath()) {
				ConfirmationDialog confirmationDialog =
						new ConfirmationDialog(this, "Missing paths", "One or more source paths are missing. Continue?");
				okd = confirmationDialog.isOk();
				confirmationDialog.dispose();
				break;
			}
		}
		return okd;
	}

	// Creates DSV files
	private void actionCreate() {
		if (showMissingPathDialog()) {
			String idpDir = PropertyUtil.getProperty(PropertyUtil.HOME_DIR) + Utilities.getSystemSeparator() + "users" + Utilities.getSystemSeparator();
			int userID;
			for (Map.Entry<Integer, Source> subject : idxSelectedSubjects.entrySet()) {
				Source source = subject.getValue();
				if (source.hasPath()) {
					userID = subject.getKey();
					String dsvDir = idpDir + userID + Utilities.getSystemSeparator() + "infiles" + Utilities.getSystemSeparator();

					int[] counter = getAccelerometerCounters(userID, dsvDir);
					cTable = counter[0];
					cAccelerometer = counter[1];

//						// List JSON files
//						List<File> files = new ArrayList<>();
//						for (String path : source.getPaths()) {
//							File dir = new File(path);
//							if (dir.exists()) {
//								files.addAll(FileListing.getFileListingNoSort(new File(path)));
//							} else {
//								System.out.println(path + " doesn't exists.");
//							}
//						}
//
//
//						Collections.sort(files, new FileComparator());
//
//						TreeSet<String> fileName = new TreeSet<>();
//						for (int i = 0; i < files.size(); i++) {
//							if (!fileName.add(files.get(i).getName())) {
//								files.remove(i);
//								i--;
//							}
//						}
//
//						// For each JSON file
//						for (File file : files) {
////						    createDSVFile(file, userID, dsvDir);
//						}


					// List JSON files
					List<File> files = new ArrayList<>();
					for (String path : source.getPaths()) {
						File dir = new File(path);
						if (dir.exists()) {
							files.addAll(FileListing.getFileListingNoSort(new File(path)));
						} else {
							System.out.println(path + " doesn't exists.");
						}
					}

					TreeSet<Path> fileSet = new TreeSet<>();
					for (File file : files) {
						fileSet.add(new Path(file.getPath(), file.getName()));
					}

					for (Path path : fileSet) {
//						System.out.println(new File(path.getPath()).getPath());
					    createDSVFile(new File(path.getPath()), userID, dsvDir);
					}

					/*Collections.sort(files, new FileComparator());

					TreeSet<String> fileName = new TreeSet<>();
					TreeSet<String> filePaths = new TreeSet<>();
					for (File file : files) {
						if (fileName.add(file.getName())) {
							filePaths.add(file.getPath());
						}
					}

					// For each JSON file
					for (String file : filePaths) {
						System.out.println(new File(file).getPath());
//					    createDSVFile(new File(file), userID, dsvDir);
					}*/

				}
			}

//			new Thread(progressRunnable).start();
//			new Thread(createRunnable).start();
		}
	}

	Runnable createRunnable = new Runnable() {

		public void run() {
			String idpDir = PropertyUtil.getProperty(PropertyUtil.HOME_DIR) + Utilities.getSystemSeparator() + "users" + Utilities.getSystemSeparator();
			int userID;
			for (Map.Entry<Integer, Source> subject : idxSelectedSubjects.entrySet()) {
				Source source = subject.getValue();
				if (source.hasPath()) {
					userID = subject.getKey();
					String dsvDir = idpDir + userID + Utilities.getSystemSeparator() + "infiles" + Utilities.getSystemSeparator();

					int[] counter = getAccelerometerCounters(userID, dsvDir);
					cTable = counter[0];
					cAccelerometer = counter[1];

					//TODO Integrate the JSON file listing with the TreeSet

					// List JSON files
					List<File> files = new ArrayList<>();
					for (String path : source.getPaths()) {
						File dir = new File(path);
						if (dir.exists()) {
							files.addAll(FileListing.getFileListingNoSort(new File(path)));
						} else {
							System.out.println(path + " doesn't exists.");
						}
					}

					TreeSet<Path> fileSet = new TreeSet<>();
					for (File file : files) {
						fileSet.add(new Path(file.getPath(), file.getName()));
					}

					for (Path path : fileSet) {
//						System.out.println(new File(path.getPath()).getPath());
					    createDSVFile(new File(path.getPath()), userID, dsvDir);
					}

					/*Collections.sort(files, new FileComparator());

					TreeSet<String> fileName = new TreeSet<>();
					TreeSet<String> filePaths = new TreeSet<>();
					for (File file : files) {
						if (fileName.add(file.getName())) {
							filePaths.add(file.getPath());
						}
					}*/

					/*// For each JSON file
					for (String file : filePaths) {
						System.out.println(new File(file).getPath());
//					    createDSVFile(file, userID, dsvDir);
					}*/

				}
			}
		}
	};

	Runnable progressRunnable = new Runnable() {
		public void run() {
			ProgressMonitor monitor = ProgressUtil.createModalProgressMonitor(FrameCreateDSV.this, 100, true, 0);
			monitor.start("Creating DSV files...");
			try {
				for (int i = 0; i < 100; i += 1) {
					fetchRecord(i);
					monitor.setCurrent("Fetching " + (i + 1) + " of 10 records from database", (i + 1) * 10);
				}
			} finally {
				// to ensure that progress dialog is closed in case of any exception
				if (monitor.getCurrent() != monitor.getTotal())
					monitor.setCurrent(null, monitor.getTotal());
			}
//			btnCreate.setEnabled(true);
		}

		private void fetchRecord(int index) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	};

	//TODO check if dsvDir existss
	public void createDSVFile(File file, int userID, String dsvDir) {
		ObjectMapper mapper = new ObjectMapper();

		String dsvSep = Utilities.getFieldSeparator();

		JsonNode attribute;
		String dataType;

		// Accelerometer
		double axisX, axisY, axisZ;
		long timestamp;

		// Wi-Fi
		String bssid, ssid, capabilities;
		int frequency, level;

		// GPS
		double altitude, latitude, longitude, accuracy, speed;
		String provider;
		int satellites;

		// NFC
		String message;
		int messageID;

		// For each JSON file
		try {
			JsonNode rootNode = mapper.readValue(file, JsonNode.class);
			for (JsonNode node : rootNode) {
				dataType = node.get(JSON.DATA_TYPE).getTextValue();

				switch (dataType) {
					case JSON.ACCELEROMETER:
						attribute = node.get(JSON.FRAME);
						Iterator<JsonNode> ite = attribute.getElements();

						while (ite.hasNext()) {
							JsonNode accelerometer = ite.next();
							axisX = accelerometer.get(0).getDoubleValue();
							axisY = accelerometer.get(1).getDoubleValue();
							axisZ = accelerometer.get(2).getDoubleValue();
							timestamp = accelerometer.get(3).getLongValue();

							cAccelerometer++;

							if (cAccelerometer > JSON.ACC_COUNT) {
								cAccelerometer = 1;
								cTable++;
							}

							Utilities.saveDataFile(dsvDir + "accelerometer_" + userID + "_" + cTable +
									".dsv", axisX + dsvSep + axisY + dsvSep + axisZ + dsvSep + timestamp + dsvSep +
									userID + "\n");
						}

						break;

					case JSON.WIFI:
						bssid = node.get(JSON.BSSID).getTextValue();
						ssid = node.get(JSON.SSID).getTextValue();
						capabilities = node.get(JSON.CAPABILITIES).getTextValue();
						frequency = node.get(JSON.FREQUENCY).getIntValue();
						level = node.get(JSON.LEVEL).getIntValue();
						timestamp = node.get(JSON.TIMESTAMP).getLongValue();

						Utilities.saveDataFile(dsvDir + "wifi.dsv", bssid + dsvSep + capabilities + dsvSep +
								frequency + dsvSep + level + dsvSep + ssid + dsvSep + timestamp + dsvSep +
								userID + "\n");
						break;
					case JSON.GPS:
						accuracy = node.get(JSON.ACCURACY).getDoubleValue();
						altitude = node.get(JSON.ALTITUDE).getDoubleValue();
						longitude = node.get(JSON.LONGITUDE).getDoubleValue();
						latitude = node.get(JSON.LATITUDE).getDoubleValue();
						speed = node.get(JSON.SPEED).getDoubleValue();
						provider = node.get(JSON.PROVIDER).getTextValue();
						satellites = node.get(JSON.SATELLITES).getIntValue();
						timestamp = node.get(JSON.TIMESTAMP).getLongValue();

						Utilities.saveDataFile(dsvDir + "gps.dsv", accuracy + dsvSep +
								altitude + dsvSep + latitude + dsvSep + longitude + dsvSep + provider +
								dsvSep + satellites + dsvSep + speed + dsvSep + timestamp + dsvSep + userID + "\n");
						break;

					case JSON.NFC:
						message = node.get(JSON.MESSAGE).getTextValue();
						messageID = NFCActivity.getMessageID(message);
						timestamp = node.get(JSON.TIMESTAMP).getLongValue();

						Utilities.saveDataFile(dsvDir + "nfc.dsv", message + dsvSep + messageID + dsvSep +
								timestamp + dsvSep + userID + "\n");
						break;
				}
			}

		} catch (Exception e) {
			System.err.println("Error loading file " + file.getPath());
//			e.printStackTrace();
		}
	}

	/**
	 * Gets the number of accelerometer tables created
	 * and the quantity of samples stored in the last table.
	 *
	 * @param userID a valid user's ID.
	 * @param dir    the path of the infiles folder from the user (@code userID).
	 * @return an array with the counters.
	 */
	private int[] getAccelerometerCounters(int userID, String dir) {
		int tableID = 0;
		int count = 500000;
		File dsvDir = new File(dir);
		FilenameFilter filenameFilter = new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.endsWith(".dsv") && name.startsWith("accelerometer");
			}
		};
		File[] files = dsvDir.listFiles(filenameFilter);
		if (files != null && files.length > 0) {
			long lastMod = Long.MIN_VALUE;
			File lastFile = files[0];
			for (File file : files) {
				if (file.lastModified() > lastMod) {
					lastFile = file;
					lastMod = file.lastModified();
				}
			}
			count = Utilities.getLineCount(lastFile);
			String lastFilename = lastFile.getName();
			tableID = Integer.valueOf(lastFilename.substring(lastFilename.lastIndexOf("_") + 1, lastFilename.indexOf(".")));
		} else {
			ResultSet resultSet = Query.getUserTables(userID);
			if (resultSet != null) {
				try {
					if (resultSet.next()) {
						tableID = resultSet.getInt(1);
					}

					if (tableID > 0) {
						resultSet = Query.getAccelerometerCount(userID, tableID);
						if (resultSet != null && resultSet.next()) {
							count = resultSet.getInt(1);
						}
					}

				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			Query.close();
		}

		return new int[]{tableID, count};
	}

	private void actionCancel() {
		//TODO reset/reload values?
		closeWindow(true);
	}

	private void enableComponents() {
		boolean selected = !btnOk.isSelected();

		lSelectedSubjects.setEnabled(selected);
		lSubjects.setEnabled(selected);
		btnAdd.setEnabled(selected);
		btnRemove.setEnabled(selected);
		btnAll.setEnabled(selected);
		btnNone.setEnabled(selected);
		btnCancelSelected.setEnabled(selected);

		lPaths.setEnabled(!selected);
		btnExplore.setEnabled(!selected && !dlmUnsortedSelectedSubjects.isEmpty());
		btnCreate.setEnabled(!selected && !dlmPaths.isEmpty());
	}

	private String getSpaces(int userID) {
		String ss = " ";
		if (userID < 10) {
			ss = "      ";
		} else if (userID < 100) {
			ss = "    ";
		} else if (userID < 1000) {
			ss = "  ";
		}
		return ss;
	}

	private int getUserID(String s) {
		return Integer.valueOf(s.substring(0, s.indexOf(" ")));
	}


	public static void main(String[] a) {
		SwingUtil.setUIManager();
		new FrameCreateDSV().setVisible(true);
	}


	class SelectedListCellRenderer extends DefaultListCellRenderer {
		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
			Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
			if (idxSubjectsPerRow.get(index).isSelected() && !isSelected) {
				c.setBackground(SwingUtil.colorInsert);
			}
			return c;
		}
	}

	class Source {
		//		private List<String> paths = new ArrayList<>();
		private TreeSet<String> paths = new TreeSet<>();
		private Object object;

		public Source(Object object) {
			this.object = object;
		}

		public void setPath(String path) {
			paths.clear();
			paths.add(path);
		}

		public void appendPath(List<String> paths) {
			this.paths.addAll(paths);
		}

		public void appendPath(String path) {
			paths.add(path);
		}

		public void appendPath(File[] paths) {
//			paths.clear();
			for (File file : paths) {
				appendPath(file.getPath());
			}
		}

		public String getPath() {
			String pathString = "";
			for (String path : paths) {
				pathString += "\"" + path + "\" ";
			}
			if (pathString.length() == 0) {
				return " ";
			} else {
				return pathString;
			}
		}

		public TreeSet<String> getPaths() {
			return paths;
		}

		public String printObject() {
			return object.toString();
		}

		public Object getObject() {
			return object;
		}

		public boolean hasPath() {
			return !paths.isEmpty();
		}
	}

	class Path implements Comparable<Path> {

		private String path;
		private String filename;

		public Path(String path, String filename) {
			this.path = path;
			this.filename = filename;
		}

		@Override
		public int compareTo(Path o) {
			return this.getFilename().compareTo(o.getFilename());
		}

		public boolean equals(Path o) {
			return o.getFilename().equals(this.getFilename());
		}

		public String getPath() {
			return path;
		}

		public String getFilename() {
			return filename;
		}
	}
}
